package io.cici.server.web.controller;

import io.cici.common.APIConstant;
import io.cici.common.Query;
import io.cici.common.enums.TaskInstanceStatus;
import io.cici.common.request.http.SaveJobInfoRequest;
import io.cici.common.response.InstanceInfoDTO;
import io.cici.common.response.ResultDTO;
import io.cici.server.core.hide.service.AppInfoService;
import io.cici.server.core.hide.service.CacheService;
import io.cici.server.core.hide.service.JobService;
import io.cici.server.core.instance.InstanceService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 开放接口（OpenAPI）控制器，对接 oms-client
 *
 * @author tjq
 * @since 2020/4/15
 */
@RestController
@RequestMapping(APIConstant.WEB_PATH)
@RequiredArgsConstructor
public class OpenAPIController {

    private final AppInfoService appInfoService;

    private final JobService jobService;

    private final InstanceService instanceService;


    private final CacheService cacheService;


    @PostMapping(APIConstant.ASSERT)
    public ResultDTO<Long> assertAppName(String appName, @RequestParam(required = false) String password) {
        return ResultDTO.success(appInfoService.assertApp(appName, password));
    }

    /* ************* Job 区 ************* */

    @PostMapping(APIConstant.SAVE_JOB)
    public ResultDTO<Long> saveJob(@RequestBody SaveJobInfoRequest request) {
        if (request.getId() != null) {
            checkJobIdValid(request.getId(), request.getAppId());
        }
        return ResultDTO.success(jobService.saveJob(request));
    }


    @PostMapping(APIConstant.RUN_JOB)
    public ResultDTO<Long> runJob(Long appId, Long jobId, @RequestParam(required = false) String instanceParams, @RequestParam(required = false) Long delay) {
        checkJobIdValid(jobId, appId);
        return ResultDTO.success(jobService.runJob(appId, jobId, instanceParams, delay));
    }

    /* ************* Instance 区 ************* */

    @PostMapping(APIConstant.STOP_INSTANCE)
    public ResultDTO<Void> stopInstance(Long instanceId, Long appId) {
        checkInstanceIdValid(instanceId, appId);
        instanceService.stopTaskInstance(appId, instanceId);
        return ResultDTO.success(null);
    }

    @PostMapping(APIConstant.CANCEL_INSTANCE)
    public ResultDTO<Void> cancelInstance(Long instanceId, Long appId) {
        checkInstanceIdValid(instanceId, appId);
        instanceService.cancelInstance(appId, instanceId);
        return ResultDTO.success(null);
    }

    @PostMapping(APIConstant.RETRY_INSTANCE)
    public ResultDTO<Void> retryInstance(Long instanceId, Long appId) {
        checkInstanceIdValid(instanceId, appId);
        instanceService.retryInstance(appId, instanceId);
        return ResultDTO.success(null);
    }

    @PostMapping(APIConstant.FETCH_INSTANCE_STATUS)
    public ResultDTO<Integer> fetchInstanceStatus(Long instanceId) {
        TaskInstanceStatus taskInstanceStatus = instanceService.getInstanceStatus(instanceId);
        return ResultDTO.success(taskInstanceStatus.getCode());
    }

    @PostMapping(APIConstant.FETCH_INSTANCE_INFO)
    public ResultDTO<InstanceInfoDTO> fetchInstanceInfo(Long instanceId) {
        return ResultDTO.success(instanceService.getInstanceInfo(instanceId));
    }

    @PostMapping(APIConstant.QUERY_INSTANCE)
    public ResultDTO<List<InstanceInfoDTO>> queryInstance(@RequestBody Query query) {
        return ResultDTO.success(instanceService.queryInstanceInfo(query));
    }


    private void checkInstanceIdValid(Long instanceId, Long appId) {
        Long realAppId = cacheService.getAppIdByInstanceId(instanceId);
        if (realAppId == null) {
            throw new IllegalArgumentException("can't find instance by instanceId: " + instanceId);
        }
        if (appId.equals(realAppId)) {
            return;
        }
        throw new IllegalArgumentException("instance is not belong to the app whose appId is " + appId);
    }

    private void checkJobIdValid(Long jobId, Long appId) {
        Long realAppId = cacheService.getAppIdByJobId(jobId);
        // 查不到，说明 jobId 不存在
        if (realAppId == null) {
            throw new IllegalArgumentException("can't find job by jobId: " + jobId);
        }
        // 不等，说明该job不属于该app，无权限操作
        if (!appId.equals(realAppId)) {
            throw new IllegalArgumentException("this job is not belong to the app whose appId is " + appId);
        }
    }
}
